﻿using System;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Xml;

namespace BoldBrick.Core.Xml
{
	/// <summary>
	/// This class provides XML serialization and deserialization
	/// </summary>
    public static class XmlSerialization
    {
        #region Deserialization
		
		/// <summary>
		/// Deserializes <see cref="string"/> data into <see cref="TType"/> object
		/// </summary>
		/// <typeparam name="TType">Type of deserialzed object</typeparam>
		/// <param name="data">Serialized string data of the object</param>
		/// <returns>Returns deserialized <see cref="string"/> data into <see cref="TType"/> object</returns>
        public static TType DeserializeString<TType>(string data)
            where TType : class
        {
            using (StringReader sr = new StringReader(data))
                return Deserialize<TType>(sr);
        }

		/// <summary>
		/// Deserializes data from <paramref name="sourceFilePath"/> file into <see cref="TType"/> object
		/// </summary>
		/// <typeparam name="TType">Type of deserialzed object</typeparam>
		/// <param name="sourceFilePath">File with serialized object</param>
		/// <returns>Returns deserialized data from <paramref name="sourceFilePath"/> file into <see cref="TType"/> object</returns>
		public static TType Deserialize<TType>(string sourceFilePath)
            where TType : class
        {
            // A FileStream is needed to read the XML document.
            using (FileStream fs = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read))
            {
                // Use the Deserialize method to restore the object's state.
                return Deserialize<TType>(
                    new XmlTextReader(fs));
            }
        }

		/// <summary>
		/// Deserializes data from <paramref name="reader"/> reader into <see cref="TType"/> object
		/// </summary>
		/// <typeparam name="TType">Type of deserialzed object</typeparam>
		/// <param name="reader"><see cref="XmlReader"/> of data</param>
		/// <returns>Returns deserialized data from <paramref name="reader"/> reader into <see cref="TType"/> object</returns>
		public static TType Deserialize<TType>(XmlReader reader)
        {
            try
            {
                // Create an instance of the XmlSerializer specifying type
                XmlSerializer serializer = new XmlSerializer(typeof(TType));

                // Use the Deserialize method to restore the object's state.
                return (TType)serializer.Deserialize(reader);
            }
            catch (InvalidOperationException ex)
            {
                throw new XmlSerializationException("Error in deserialization", ex);
            }
        }

		/// <summary>
		/// Deserializes data from <paramref name="reader"/> reader into <see cref="TType"/> object
		/// </summary>
		/// <typeparam name="TType">Type of deserialzed object</typeparam>
		/// <param name="reader"><see cref="TextReader"/> of data</param>
		/// <returns>Returns deserialized data from <paramref name="reader"/> reader into <see cref="TType"/> object</returns>
        public static TType Deserialize<TType>(TextReader reader)
        {
            // Create an instance of the XmlSerializer specifying type
            XmlSerializer serializer = new XmlSerializer(typeof(TType));

            // Use the Deserialize method to restore the object's state.
            return (TType)serializer.Deserialize(reader);
        }

		/// <summary>
		/// Deserializes data from <paramref name="source"/> reader into <see cref="TType"/> object
		/// </summary>
		/// <typeparam name="TType">Type of deserialzed object</typeparam>
		/// <param name="source"><see cref="StringReader"/> of data</param>
		/// <returns>Returns deserialized data from <paramref name="source"/> reader into <see cref="TType"/> object</returns>
		public static TType Deserialize<TType>(StringReader source)
            where TType : class
        {
            // read string as XML
            using (XmlReader reader = new XmlTextReader(source))
            {
                // Use the Deserialize method to restore the object's state.
                return Deserialize<TType>(reader);
            }
        }
        #endregion

        #region Serialization
		
		/// <summary>
		/// Serializes <paramref name="obj"/> object into <paramref name="destFilePath"/> file
		/// </summary>
		/// <param name="obj">Object to serialize</param>
		/// <param name="destFilePath">Destination file</param>
        public static void Serialize(object obj, string destFilePath)
        {
            /* Create a StreamWriter to write with. First create a FileStream
               object, and create the StreamWriter specifying an Encoding to use. */
            using (TextWriter tw = new StreamWriter(destFilePath))
                Serialize(tw, obj);
        }

		/// <summary>
		/// Serializes <paramref name="obj"/> object into <paramref name="destFilePath"/> file with specified <paramref name="encoding"/>
		/// </summary>
		/// <param name="obj">Object to serialize</param>
		/// <param name="destFilePath">Destination file</param>
		/// <param name="encoding">Encoding of serialization</param>
		public static void Serialize(object obj, string destFilePath, Encoding encoding)
        {
            /* Create a StreamWriter to write with. First create a FileStream
               object, and create the StreamWriter specifying an Encoding to use. */
            using (TextWriter tw = new StreamWriter(destFilePath, false, encoding))
                Serialize(tw, obj);
        }

		/// <summary>
		/// Serializes <paramref name="obj"/> object into <see cref="StringWriter"/> object
		/// </summary>
		/// <param name="obj">Object to serialize</param>
        public static StringWriter Serialize(object obj)
        {
            StringWriter sw = new StringWriter();

            Serialize(sw, obj);

            return sw;
        }

		/// <summary>
		/// Serializes <paramref name="obj"/> object into <see cref="TextWriter"/> object
		/// </summary>
		/// <param name="tw"><see cref="TextWriter"/> object for serialization</param>
		/// <param name="obj">Object to serialize</param>
		/// <param name="objType">Type of object to serialize</param>
		public static void Serialize(TextWriter tw, object obj, Type objType)
        {
            XmlSerializer serializer = new XmlSerializer(objType);
            serializer.Serialize(tw, obj);
        }

		/// <summary>
		/// Serializes <paramref name="obj"/> object into <see cref="XmlWriter"/> object
		/// </summary>
		/// <param name="tw"><see cref="XmlWriter"/> object for serialization</param>
		/// <param name="obj">Object to serialize</param>
		/// <param name="objType">Type of object to serialize</param>
        public static void Serialize(XmlWriter tw, object obj, Type objType)
        {
            XmlSerializer serializer = new XmlSerializer(objType);
            serializer.Serialize(tw, obj);
        }

		/// <summary>
		/// Serializes <paramref name="obj"/> object into <see cref="TextWriter"/> object
		/// </summary>
		/// <typeparam name="TType">Type of object to serialize</typeparam>
		/// <param name="tw"><see cref="TextWriter"/> object</param>
		/// <param name="obj">Object to serialize</param>
		public static void Serialize<TType>(TextWriter tw, TType obj)
			where TType : class
        {
			Serialize(tw, obj, typeof(TType));
        }

		/// <summary>
		/// Serializes <paramref name="obj"/> object into <see cref="XmlWriter"/> object
		/// </summary>
		/// <typeparam name="TType">Type of object to serialize</typeparam>
		/// <param name="tw"><see cref="XmlWriter"/> object</param>
		/// <param name="obj">Object to serialize</param>
        public static void Serialize<TType>(XmlWriter tw, TType obj)
            where TType : class
        {
            Serialize(tw, obj, typeof(TType));
        }

		/// <summary>
		/// Serializes <paramref name="obj"/> object into <see cref="TextWriter"/> object
		/// </summary>
		/// <param name="tw"><see cref="TextWriter"/> object</param>
		/// <param name="obj">Object to serialize</param>
        public static void Serialize(TextWriter tw, object obj)
        {
            Serialize(tw, obj, obj.GetType());
        }

		/// <summary>
		/// Serializes <paramref name="obj"/> object into <see cref="XmlWriter"/> object
		/// </summary>
		/// <param name="tw"><see cref="XmlWriter"/> object</param>
		/// <param name="obj">Object to serialize</param>
        public static void Serialize(XmlWriter tw, object obj)
        {
            Serialize(tw, obj, obj.GetType());
        }

		/// <summary>
		/// Serializes <paramref name="obj"/> object into <see cref="string"/>
		/// </summary>
		/// <param name="obj">Object to serialize</param>
		/// <returns>Returns serialized <see cref="string"/> of <paramref name="obj"/></returns>
        public static string SerializeToString(object obj)
        {
            using (StringWriter sw = Serialize(obj))
                return sw.ToString();
        }

        #endregion
    }
}
